﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Timers;
using LogLib;
using System.Threading.Tasks;

namespace KXmlUIControl.KControl
{
    public partial class CountdownControl : UserControl, INotifyPropertyChanged
    {
        public delegate void UpdatePropertyDelegate(string strName);
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (this.InvokeRequired)
            {
                UpdatePropertyDelegate outdelegate = new UpdatePropertyDelegate(RaisePropertyChanged);
                this.Invoke(outdelegate, new object[] { propertyName });
                return;
            }
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected event CountdownCompletedEventHandler CountdownCompleted;
        public void OnCountdownCompleted(EventArgs e)
        {
            if (CountdownCompleted != null)
            {
                CountdownCompleted(this, e);
            }
        }

        public event CountdownClosingEventHandler CountdownClosing;
        public void OnCountdownClosing(EventArgs e)
        {
            if (CountdownClosing != null)
            {
                CountdownClosing(this, e);
            }
        }

        private object _lockState = new object();

        /// <summary>
        /// 倒计时是否正在运行
        /// </summary>
        private bool _isRunning = false;
        public bool IsRunning
        {
            get
            {
                return _isRunning;
            }
        }

        /// <summary>
        /// 倒计时是否暂停
        /// </summary>
        private bool _paused = false;
        [DefaultValue(false)]
        public bool Paused
        {
            get
            {
                return _paused;
            }
            set
            {
                _paused = value;
                _isRunning = false;
                if (value && timer != null)
                {
                    timer.Stop();
                }
            }
        }

        /// <summary>
        /// 倒计时秒数
        /// </summary>
        private int _countDownSecond = 10;
        [DefaultValue(10)]
        public int CountDownSecond
        {
            get
            {
                return _countDownSecond;
            }
            set
            {
                if (_countDownSecond != value)
                {
                    _countDownSecond = value;
                    if (this.IsDisposed)
                    {
                        return;
                    }
                    if (!this.InvokeRequired)
                    {
                        labelTimeInfo.Text = value.ToString();
                    }
                    if (this.IsDisposed)
                    {
                        return;
                    }
                    this.RaisePropertyChanged("CountDownSecond");
                    if (this.IsDisposed)
                    {
                        return;
                    }
                    RefreshSelf();
                }
            }
        }

        private System.Timers.Timer timer;
        private SynchronizationContext context;
        private int syncPoint;
        public string ParentName 
        {
            private set;
            get;
        }

        public CountdownControl()
        {
            this.Visible = false;
            SetStyles();
            InitializeComponent();
            labelTimeInfo.DataBindings.Add("Text", this, "CountDownSecond");
            //labelTimeInfo.Text = CountDownSecond.ToString();
            if (_countDownSecond > 999)
            {
                this.Size = new Size(165, 165);
            }
            context = SynchronizationContext.Current;
            InitTimer();
        }

        public void SetParentName(string name)
        {
            ParentName = name;
        }

        public void SetStyles()
        {
            this.DoubleBuffered = true;//设置本窗体
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
            SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲
        }

        private void InitTimer()
        {
            Log.WriteAsync($"页面{ParentName}对倒计时执行初始化.");
            labelTimeInfo.Text = CountDownSecond.ToString();
            timer = new System.Timers.Timer();
            timer.Interval = 1000;
            timer.AutoReset = true;
            timer.Elapsed += Timer_Elapsed;
            syncPoint = 0;
            LogSyncPointValue();
        }

        public void RefreshSelf()
        {
            try
            {
                if (this.IsDisposed)
                {
                    return;
                }
                if (this.InvokeRequired)
                {
                    Action outdelegate = new Action(RefreshSelf);
                    this.Invoke(outdelegate);
                    return;
                }
                this.Refresh();
            }
            catch (Exception ex)
            {
                Log.WriteExceptionAsync(ex.ToString());
            }
        }

        public async Task Start(CountdownCompletedEventHandler handler)
        {
            await Task.Run(async() =>
            {
                try
                {
                    if (timer == null)
                    {
                        InitTimer();
                    }
                    if (timer != null && timer.Enabled)
                    {
                        await Stop();
                    }
                    context.Post(delegate
                    {
                        this.Visible = true;
                    }, null);
                    CountdownCompleted = null;
                    CountdownCompleted += handler;
                    timer.Start();
                    Log.WriteAsync($"页面{ParentName}倒计时Timer开始运行，CountDownSecond={this.CountDownSecond}");
                    _isRunning = true;
                }
                catch (Exception ex)
                {
                    Log.WriteException(ex.ToString());
                }
            });         
        }

        public void RemoveEvent()
        {
            CountdownCompleted = null;
            CountdownClosing = null;
        }

        public async Task Stop()
        {
            await Task.Run(() =>
            {
                Log.WriteAsync($"页面{ParentName}: Stop in");
                CountdownCompleted = null;
                if (timer == null || !timer.Enabled)
                {
                    Log.WriteAsync($"不必要的操作：页面{ParentName}倒计时Timer已停止.");
                    Log.WriteAsync($"页面{ParentName}: Stop out");
                    return;
                }
                int count = 0;
                LogSyncPointValue();
                try
                {                  
                    while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0 && count < 10)
                    {
                        Log.WriteAsync($"页面{ParentName}停止倒计时操作陷入等待.");
                        Thread.Sleep(50);
                        count++;
                    }
                    LogSyncPointValue();
                    context.Post(delegate
                    {
                        this.Visible = false;
                    }, null);
                    if (timer != null)
                    {
                        timer.Stop();
                    }
                    _isRunning = false;
                    Log.WriteAsync($"页面{ParentName}倒计时停止成功.");
                }
                catch (Exception ex)
                {
                    Log.WriteException(ex.ToString());
                }
                finally
                {
                    syncPoint = 0;
                    LogSyncPointValue();
                    Log.WriteAsync($"页面{ParentName}: Stop out");
                    Log.AddBoundary($"页面{ParentName} end");
                }
            });           
        }

        private void LogSyncPointValue()
        {
            Log.WriteAsync($"页面{ParentName}: SyncPoint={syncPoint}");
        }

        public void CloseCountDown()
        {
            Task.Run(() =>
            {
                if (timer == null)
                {
                    Log.WriteAsync($"不必要的操作：页面{ParentName}倒计时已关闭.");
                    return;
                }
                Log.WriteAsync($"页面{ParentName}: CloseCountDown in");
                try
                {                 
                    int count = 0;
                    LogSyncPointValue();
                    while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0 && count < 10)
                    {
                        Log.WriteAsync($"页面{ParentName}关闭倒计时操作陷入等待.");
                        Thread.Sleep(50);
                        count++;
                    }
                    LogSyncPointValue();
                    CountdownCompleted = null;
                    if(timer != null)
                    {
                        timer.Stop();
                        timer.Dispose();
                    }                 
                    timer = null;
                    _isRunning = false;
                    context.Post(delegate
                    {
                        this.Visible = false;
                    }, null);
                    Log.WriteAsync($"页面{ParentName}倒计时关闭成功.");
                }
                catch (Exception ex)
                {
                    Log.WriteException(ex.ToString());
                }
                finally
                {
                    syncPoint = 0;
                    LogSyncPointValue();
                    Log.WriteAsync($"页面{ParentName}: CloseCountDown out");
                }
            });           
        }

        public async Task Restart(int countdownSec, CountdownCompletedEventHandler handler)
        {
            await Task.Run(async() =>
            {
                Log.AddBoundary($"页面{ParentName} in");
                if (timer != null && timer.Enabled)
                {
                    await Stop();
                }
                if (timer == null)
                {
                    InitTimer();
                }
                int count = 0;
                LogSyncPointValue();
                while (Interlocked.CompareExchange(ref syncPoint, 2, 0) != 0 && count < 10)
                {
                    Log.WriteAsync($"页面{ParentName}启动倒计时操作陷入等待.");
                    Thread.Sleep(50);
                    count++;
                }
                LogSyncPointValue();
                if (syncPoint != 2)
                {
                    Log.WriteAsync($"页面{ParentName}倒计时Timer重新开始运行失败.");
                    Log.WriteAsync("Restart out.");
                    return;
                }
                try
                {
                    CountDownSecond = countdownSec;
                    CountdownCompleted = null;
                    CountdownCompleted += handler;
                    timer.Start();
                    _isRunning = true;
                    _paused = false;
                    context.Post(delegate
                    {
                        SetTextColor(ForeColor);
                        this.Visible = true;
                        RefreshSelf();
                    }, null);
                    Log.WriteAsync($"页面{ParentName}倒计时Timer重新开始运行，CountDownSecond={this.CountDownSecond}");
                }
                catch (Exception ex)
                {
                    Log.WriteAsync(ex.ToString());
                }
                finally
                {
                    syncPoint = 0;
                    LogSyncPointValue();
                    Log.WriteAsync($"页面{ParentName} Restart out.");
                }
            });                  
        }

        private void Timer_Elapsed(object o, ElapsedEventArgs e)
        {
            if (_paused || CountDownSecond <= 0)
            {
                return;
            }
            if (this.IsDisposed)
            {
                return;
            }
            int count = 0;
            while (Interlocked.CompareExchange(ref syncPoint, 1, 0) != 0 && count < 5)
            {
                Log.WriteAsync($"页面{ParentName}倒计时读秒陷入等待.");
                Thread.Sleep(50);
                count++;
            }
            if (syncPoint != 1)
            {
                LogSyncPointValue();
                Log.WriteAsync($"页面{ParentName}倒计时上一次读秒{CountDownSecond}操作未结束.");
                return;
            }
            try
            {                          
                CountDownSecond--;
                if (CountDownSecond == 10)
                {
                    context.Post(delegate
                    {
                        SetTextColor(Color.Red);
                    }, null);
                }
                else if (CountDownSecond == 2)
                {
                    OnCountdownClosing(new EventArgs());
                }
                else if (CountDownSecond == 0)
                {
                    _isRunning = false;
                    context.Post(delegate
                    {
                        this.Visible = false;
                        if (timer != null)
                        {
                            this.Visible = false;
                        }
                        OnCountdownCompleted(new EventArgs());
                    }, null);
                    if (timer != null)
                    {
                        timer.Stop();
                        timer.Dispose();
                        timer = null;
                    }                                   
                }
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
            finally
            {
                syncPoint = 0;
            }
        }

        public void SetBackColor(Color col)
        {
            if(this.IsDisposed)
            {
                return;
            }
            this.BackColor = col;
        }

        public void SetTextColor(Color col)
        {
            if (this.IsDisposed)
            {
                return;
            }
            this.labelTimeInfo.ForeColor = col;
        }

        public void SetTextSize(int s)
        {
            if (this.IsDisposed)
            {
                return;
            }
            this.labelTimeInfo.Font = new Font("Calibri", s);
        }
    }
}
